package logic

import (
	"common/logs"
	"common/utils"
	"context"
	"core/repo"
	"core/service"
	"fmt"
	"framework/remote"
	"game_bao/component/gameBao"
	"game_bao/models/request"
	"game_bao/models/response"
	"strconv"
	"sync"
	"time"
)

const (
	UserWebTime = 5 * 60 // 用户访问时间心跳
	waitTime    = 50
)

type BaoManager struct {
	sync.RWMutex
	GameID      uint
	Rounds      int64
	peopleNum   int64
	bettingNum  int64
	users       map[uint]*response.GameFleeData //用户
	usersTimer  map[uint]*time.Timer
	gameStarted bool               //开启，关闭
	status      gameBao.FleeStatus //是否可加入
	baoTimer    *time.Timer
	gameService *service.GameService
	isOpen      int
	gameRule    request.GameBaoRule
}

func (m *BaoManager) sendDataUsers(users []string, data any, session *remote.Session) {
	m.ServerMessagePush(users, data, session)
}

// ServerMessagePush 封装socket推送
func (m *BaoManager) ServerMessagePush(users []string, data any, session *remote.Session) {
	session.Push(users, data, "ServerMessagePush")
}

func (m *BaoManager) sendMessagePush(data any) {
	for _, u := range m.users {
		m.sendDataUsers([]string{fmt.Sprintf("%d", u.UserInfo.UID)}, data, u.Session)
	}
}

func (m *BaoManager) otherUsers(uid uint) []string {
	var uids []string
	for _, v := range m.users {
		if v.UserInfo.UID == uid {
			continue
		}
		uids = append(uids, fmt.Sprintf("%d", v.UserInfo.UID))
	}
	return uids
}

// getGameRule 获取配置
func (m *BaoManager) getGameRule() request.GameBaoRule {
	ctx := context.TODO()
	data := m.gameService.GetConf(ctx, m.GameID)
	var gameRule request.GameBaoRule
	for _, v := range *data {
		if v.Name == "start_time" {
			val, _ := strconv.Atoi(v.Value)
			gameRule.StartHour = val
		} else if v.Name == "end_time" {
			val, _ := strconv.Atoi(v.Value)
			gameRule.EndHour = val
		}
	}
	return gameRule
}

func (m *BaoManager) run() {
	m.gameRule = m.getGameRule()
	go m.timerBaoStart()
}

// timerBaoStart 定时开始游戏
func (m *BaoManager) timerBaoStart() {
	now := time.Now()
	startDate := time.Date(now.Year(), now.Month(), now.Day(), m.gameRule.StartHour, 0, 0, 0, time.Local)
	endDate := time.Date(now.Year(), now.Month(), now.Day(), m.gameRule.EndHour, 0, 0, 0, time.Local)
	//当开始时间大于结束时间 为隔天结束
	if m.gameRule.StartHour > m.gameRule.EndHour {
		//当现在的时间大于0点 并且小于结束时间  为昨天的轮回
		if now.Hour() > 0 && now.Hour() < m.gameRule.EndHour {
			startDate = startDate.AddDate(0, 0, -1)
		} else {
			endDate = endDate.AddDate(0, 0, 1)
		}
	}
	var times int64
	// 现在的时间<=开始时间 && 现在的时间<=结束时间 = （未开始）开始倒计时
	if now.Unix() <= startDate.Unix() && now.Unix() <= endDate.Unix() {
		times = startDate.Unix() - now.Unix()
		m.Rounds = 0
	} else { //游戏中
		diff := now.Sub(startDate)
		hours := diff / time.Hour % 60
		minutes := diff / time.Minute % 60
		//TODO 1分钟游戏
		second := diff / time.Second % 60
		times = 60 - int64(second)
		m.Rounds = int64(minutes + hours*60)
	}
	timer := m.baoTimer
	if timer != nil {
		timer.Stop()
	}
	timer = time.AfterFunc(time.Duration(times)*time.Second, func() {
		timer.Stop()
		m.gameStarted = true
		//初始化数据
		go m.initData(time.Now())
		//启动定点执行
		go m.roomTimerHandler()
		//定时关闭
		go m.timerBaoStop()
	})
}

// timerBaoStop 定时关闭游戏
func (m *BaoManager) timerBaoStop() {
	now := time.Now()
	startDate := time.Date(now.Year(), now.Month(), now.Day(), m.gameRule.StartHour, 0, 0, 0, time.Local)
	endDate := time.Date(now.Year(), now.Month(), now.Day(), m.gameRule.EndHour, 0, 0, 0, time.Local)
	//当开始时间大于结束时间 为隔天结束
	if m.gameRule.StartHour > m.gameRule.EndHour {
		//当现在的时间大于0点 并且小于结束时间  为昨天的轮回
		if now.Hour() > 0 && now.Hour() < m.gameRule.EndHour {
			startDate = startDate.AddDate(0, 0, -1)
		} else {
			endDate = endDate.AddDate(0, 0, 1)
		}
	}
	var times int64
	times = endDate.Unix() - now.Unix()

	timer := m.baoTimer
	if timer != nil {
		timer.Stop()
	}
	timer = time.AfterFunc(time.Duration(times)*time.Second, func() {
		logs.Warn("%v财神到游戏关闭", time.Now().Format(time.DateTime))
		timer.Stop()
		m.gameStarted = false
		m.status = gameBao.StatusNone
		//重启开始
		go m.timerBaoStart()
	})
}

// initData 初始化数据
func (m *BaoManager) initData(t time.Time) {
	m.Lock()
	defer m.Unlock()
	//告诉回合数
	m.Rounds++
	logs.Warn("第%d回合,财神到游戏重置%v", m.Rounds, t.Format(time.DateTime))
}

// roomTimerHandler 游戏中定时执行业务
func (m *BaoManager) roomTimerHandler() {
	ticker := time.NewTicker(1 * time.Second)
	defer ticker.Stop()
	for {
		if m.gameStarted == false {
			break
		}
		select {
		case t := <-ticker.C:
			switch t.Second() {
			//1分钟游戏
			case 0:
				//初始化数据
				go m.initData(t)
				break
			case waitTime:
				break
			}
		}
	}
}

// checkRoomUser 检查房间用户心跳
func (m *BaoManager) checkRoomUser(session *remote.Session, data response.GameFleeInfo) {
	m.Lock()
	defer m.Unlock()
	_, ok := m.users[data.UID]
	if ok {
		//重启用户心跳
		m.usersTimer[data.UID].Reset(UserWebTime * time.Second)
		return
	}
	data.Nickname = utils.UpNickname(data.Nickname)
	m.users[data.UID] = &response.GameFleeData{
		UserInfo: data,
		Session:  session,
	}
	//添加用户心跳
	go m.scheduleUserTimerHandle(data)
}

// scheduleUserTimerHandle 心跳 定时删除用户组里的用户数据
func (m *BaoManager) scheduleUserTimerHandle(data response.GameFleeInfo) {
	m.Lock()
	defer m.Unlock()
	if m.usersTimer[data.UID] != nil {
		m.usersTimer[data.UID].Stop()
	}
	m.usersTimer[data.UID] = time.AfterFunc(UserWebTime*time.Second, func() {
		m.usersTimer[data.UID].Stop()
		m.sendDataUsers([]string{fmt.Sprint(data.UID)}, gameBao.GameOutPushData(), m.users[data.UID].Session)
		delete(m.usersTimer, data.UID)
		delete(m.users, data.UID)
	})
}

// BaoOut 退出游戏
func (m *BaoManager) BaoOut(data *response.GameFleeInfo) {
	m.Lock()
	defer m.Unlock()
	if m.users[data.UID] != nil {
		m.usersTimer[data.UID].Stop()
		delete(m.users, data.UID)
	}
}

func NewBaoManager(r *repo.Manager) *BaoManager {
	b := &BaoManager{
		GameID:      3,
		Rounds:      0,
		peopleNum:   0,
		bettingNum:  0,
		users:       make(map[uint]*response.GameFleeData),
		usersTimer:  make(map[uint]*time.Timer),
		status:      gameBao.StatusNone,
		isOpen:      0,
		gameService: service.NewGameService(r),
	}
	b.run()
	return b
}
